<?php

declare(strict_types=1);

/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */

namespace App\Model;

use Hyperf\DbConnection\Model\Model as BaseModel;
use Hyperf\Stringable\Str;

abstract class Model extends BaseModel
{
    protected $query;
    protected string $message = '';
    protected array  $data    = [];
    protected array $select = [];
    protected int $is_status_search = 1;// 默认使用 1 执行筛选 status = 1
    protected int $is_delete_search = 1;// 默认使用 1 执行筛选 is_delete = 0

    /**
     * 筛选条件
     *
     * @param $query
     * @param $value
     * @param array $params
     * @return mixed
     */
    public function searchIdAttribute($query, $value, array $params): mixed
    {
        if (empty($value)) {
            return $query;
        }
        return $query->where('id', $value);
    }

    /**
     * 列表查询
     *
     * @param array $params
     * @param array $orderBy
     * @param array $select
     * @param array $with
     * @return array
     */
    public function getList(array $params = [], array $orderBy = [], array $select = [], array $with = [])
    {
        $query = $this->catchSearch($params)
            ->catchPages($params)
            ->sortTool($orderBy)
            ->getQueryObj()
            ->select(array_merge($this->select, $select));

        // 模型关联
        count($with) > 0 && $query->with($with);

        // 规避 禁用 和 删除 数据
        $this->is_status_search === 1 && $query->where('status', 1);
        $this->is_delete_search === 1 && $query->where('is_delete', 0);

        return $this->catchData($query->get()->toArray());
    }

    /**
     * 获取总数
     * @param array $params
     * @return mixed
     */
    public function getTotal(array $params = [])
    {
        $query = $this->catchSearch($params)->getQueryObj();

        // 规避 禁用 和 删除 数据
        $this->is_status_search === 1 && $query->where('status', 1);
        $this->is_delete_search === 1 && $query->where('is_delete', 0);

        return $query->count();
    }

    /**
     * 单条数据查询
     * @param array $params
     * @param array $orderBy
     * @param array $select
     * @param array $with
     * @return array
     */
    public function getDetail(array $params = [], array $orderBy = [], array $select = [], array $with = [])
    {
        $query = $this->catchSearch($params)
            ->catchPages($params)
            ->sortTool($orderBy)
            ->getQueryObj()
            ->select(array_merge($this->select, $select));

        // 模型关联
        count($with) > 0 && $query->with($with);

        // 规避 禁用 和 删除 数据
        $this->is_status_search === 1 && $query->where('status', 1);
        $this->is_delete_search === 1 && $query->where('is_delete', 0);

        $detail = $query->first();
        if ($detail){
            $detail = $detail->toArray();
        }else{
            $detail = [];
        }

        return $this->catchData($detail);
    }

    /**
     * 查询器
     *
     * @param array $params
     * @return $this
     */
    protected function catchSearch(array $params = [])
    {
        $this->query = !empty($this->query) ? $this->query : $this;
        if (empty($params)) {
            return $this;
        }

        foreach ($params as $field => $value) {
            $method = 'search' . Str::studly($field) . 'Attribute';
            if ($value !== null && $value !== '' && method_exists($this, $method)) {
                $this->query = $this->$method($this->query,$value,$params);
            }
        }

        return $this;
    }

    /**
     * 分页器
     *
     * @param $params
     * @return $this
     */
    protected function catchPages($params)
    {
        $this->query = !empty($this->query) ? $this->query : $this;
        if (empty($params['page']) && empty($params['size'])){
            return $this;
        }
        $page = intval($params['page'] ?? 1);
        $size = intval($params['size'] ?? 15);
        $this->query = $this->query->offset(($page - 1) * $size)->limit($size);
        return $this;
    }

    /**
     * 排序工具
     *
     * @param $orderBy
     * @return $this
     */
    protected function sortTool($orderBy)
    {
        $this->query = !empty($this->query) ? $this->query : $this;
        if (empty($orderBy)){
            return $this;
        }
        foreach ($orderBy as $sort=>$order){
            if (empty($sort) || empty($order)){
                continue;
            }
            $this->query = $this->query->orderBy($sort,$order);
        }
        return $this;
    }

    /**
     * 数据集处理器
     * @param array $data
     * @return array
     */
    protected function catchData(array $data): array
    {
        if (isset($data[0])){
            foreach ($data as $key=>$val){
                foreach ($val as $k=>$v){
                    $method = 'data' . Str::studly($k) . 'Attribute';
                    if (method_exists($this, $method)) {
                        $data[$key][$k] = $this->$method($v,$data);
                    }
                }
            }
        }else{
            foreach ($data as $key=>$val){
                $method = 'data' . Str::studly($key) . 'Attribute';
                if (method_exists($this, $method)) {
                    $data[$key] = $this->$method($val,$data);
                }
            }
        }

        return $data;
    }

    /**
     * @return mixed
     */
    protected function getQueryObj()
    {
        return $this->query;
    }

    /**
     * 返回成功结果
     * @param string $message
     * @param array $data
     * @return bool
     */
    protected function success(string $message = 'success',array $data = []): bool
    {
        $this->message = $message;
        $this->data = $data;
        return true;
    }

    /**
     * 返回失败结果
     * @param string $message
     * @param array $data
     * @return bool
     */
    protected function error(string $message = 'error',array $data = []): bool
    {
        $this->message = $message;
        $this->data = $data;
        return false;
    }

    /**
     * 获取成功数据
     * @return array
     */
    public function getData(): array
    {
        return $this->data;
    }

    /**
     * 获取消息
     * @return string
     */
    public function getMessage(): string
    {
        return $this->message;
    }
}
